<?php


namespace app\common\service;


use app\admin\model\QClass as ClassModel;
use app\admin\model\QuestionData as QDataModel;
use app\admin\model\QuestionFormat as QModel;
use app\common\enum\Questionnaire as QEnum;
// use app\common\model\User as UserModel;

class Question
{
    //获取分类列表
    public static function getQuestionnaireClassList($onlyAvailable=false)
    {
        $classData = new ClassModel();
        return $classData->getQuestionnaireClassList($onlyAvailable);
    }

    //获取所有问卷模板
    public static function getAllQuestionnaireModel()
    {
        $classData = new QModel();
        return $classData->getAllQuestionnaireModel();
    }





    /**
     * 问卷打分
     * @throws \Exception
     */
    public static function computeMark($formatModel,$data){
        if($formatModel['is_automatic']==0){
            exception('对非打分问卷进行打分，服务器错误');
        }
        $mark = 0;
        foreach ($data as $value){
            $mark+=$formatModel['format'][$value['id']]['score'][$value['choice']];
        }
        return $mark;
    }


    /***
     * 用户填写列表
     */
    public static function getUserDoneList($uid){
        return QDataModel::getUserDoneList($uid);
    }

    /***
     * 获取问卷数据详情
     */
    public static function getQuestionnaireDataDetail($id){
        return QDataModel::getQuestionnaireDataDetail($id);
    }

    /***
     * 获取统计数据（已填数和不及格数）
     */
    // public static function getStatistic($uid){
    //     return UserModel::get($uid)->visible(['questionnaire_count','not_pass_count','report_count','need_view','announcement_view']);
    // }


    /*-验证参数--*/


    /*
     * 验证定义问卷参数
     * 1.验证参数是否齐全或多余，类型是否正确
     * 2.验证语义是否正确
     * 3.验证问卷模板中的参数是否正确：
     *      a.  验证参数是否齐全或多余
     *      b.  根据题型验证参数语义是否正确
     *
     * */
    public static function checkAddQuestionnaireParam($data)
    {
        $correctData = QEnum::getParamAddQFormatNeed();
        //检查参数是否缺漏
        foreach ($correctData as $key => $value) {
            if (!array_key_exists($key, $data)) {
                echo $key;
                return false;
            }

        }
        //检查参数是否多余，是否符合类型
        // foreach ($data as $key => $value) {
        //     if (array_key_exists($key, $correctData)) {
        //         if (!checkValueType($value, $correctData[$key])) {
        //             // var_dump($key);
        //             // var_dump($value);
        //             // var_dump($correctData[$key]);
        //             return false;
        //         }
        //     } else {
        //         return false;
        //     }
        // }

        //检查参数是否符合语义
        //已经在别处验证q_class_id是否有实例对应
        //验证问卷题型格式
        if (!($check = self::checkFormat($data['format'], $data['is_automatic']))) {
            return false;
        }else if(is_string($check)){
            return $check;
        }
        //验证分数显示模式
        if (!array_key_exists($data['show_mode'], QEnum::getMarkShowMode())) {
            return false;
        }
        //验证及格分与满分关系
        if ($data['pass_mark'] < 0 || $data['pass_mark'] > $data['full_mark']) {
            return false;
        }
        return true;
    }

    /*
     * 验证问卷题型格式
     * 遍历每一题根据题型分类（不允许有设定以外的题型）
     * 1.验证参数是否齐全或多余，类型是否正确
     * 2.验证语义是否正确
     * */
    private static function checkFormat($format, $is_automatic)
    {
        //正确的题型原则
        $correctData = QEnum::getQuestionType();
        //不能为空
        if(count($format)==0){
            return false;
        }
        $lastJumpId = -1;//上一题跳题id
        $checkJumpInteract = -1;//上一个跳题最远的跳点
        //检查每一题
        foreach ($format as $key=>$value) {
            //先保证type符合语义
            if (!array_key_exists('type', $value) || !array_key_exists($value['type'], $correctData)) {
                return false;
            }
            //判断有无与自动打分题型规则相悖
            if (($is_automatic && $value['type'] != 5) || (!$is_automatic && $value['type'] == 5)) {
                return false;
            }
            $correct = $correctData[$value['type']];
            //检查该题型参数是否缺漏
            foreach ($correct as $k => $v) {
                if (!array_key_exists($k, $value)) {
                    return false;
                }
            }
            //检查参数是否多余，是否符合类型
            foreach ($value as $k => $v) {
                if (array_key_exists($k, $correct)) {
                    if (!checkValueType($v, $correct[$k])) {
                        return false;
                    }
                } else {
                    return false;
                }
            }
            //检查参数是否符合语义(对不同的题型有不同处理)
            switch ($value['type']) {
                case 0:
                    if (!self::checkIdentifyType0($value))
                        return false;
                    break;
                case 1:
                    if (!self::checkIdentifyType1($value))
                        return false;
                    break;
                case 2:
                    if (!self::checkIdentifyType2($value))
                        return false;
                    break;
                case 3:
                    if (!self::checkIdentifyType3($value))
                        return false;
                    break;
                case 4:
                    if (!self::checkIdentifyType4($value))
                        return false;
                    break;
                case 5:
                    if (!self::checkIdentifyType5($value))
                        return false;
                    break;
                case 6:
                    if (!self::checkIdentifyType6($value,$key,count($format))){
                        return false;
                    }
                    //判断此题有没有位于前面跳题范围内
                    if($key+1<$checkJumpInteract){
                        $ti=$key +1;
                        return "跳题单选之间不能有交集，第".$ti."题最远跳到第".($checkJumpInteract+1)."题，第".($key+1)."位于此范围内！";
                    }
                    //记录跳题的最远点
                    foreach ($value['jump'] as $item){
                        if($item>$checkJumpInteract){
                            $checkJumpInteract = $item;
                        }
                    }
                    $lastJumpId = $key +1;
                    break;

                      case 7:
                    if (!self::checkIdentifyType7($value))
                        return false;
                    break;
                default:
                    return false;
            }
        }
        return true;
    }


    //检验定义问卷参数中 题型0（单选）的语义正确性
    private static function checkIdentifyType0($value)
    {
        //数量和列表实际元素数一致
        if ($value['option_num'] != count($value['option'])) {
            return false;
        }
        //other_option 要在选项中或者为-1
        if($value['other_option']!=-1){
            if(!array_key_exists($value['other_option'],$value['option'])){
                return false;
            }
        }
        return true;
    }

    //检验定义问卷参数中 题型1（多选）的语义正确性
    private static function checkIdentifyType1($value)
    {
        if ($value['option_num'] != count($value['option'])) {
            return false;
        }
        //最小1，最大不超过总数，最小值小于最大值
        if ($value['min_choice'] < 1 || $value['max_choice'] > $value['option_num'] || $value['min_choice'] > $value['max_choice']) {
            return false;
        }
        //other_option 要在选项中或者为-1
        if($value['other_option']!=-1){
            if(!array_key_exists($value['other_option'],$value['option'])){
                return false;
            }
        }
        return true;
    }

    //检验定义问卷参数中 题型2（填空列表）的语义正确性
    private static function checkIdentifyType2($value)
    {
        $count = array_count_values($value['text_list']);
        $blank_count = 0;
        if (array_key_exists(QEnum::BLANK_MARK, $count)) {
            $blank_count = $count[QEnum::BLANK_MARK];
        }
        if ($value['blank_num'] != $blank_count) {
            return false;
        }
        if ($value['blank_num'] != count($value['blank_rule'])) {
            return false;
        }
        if (!QEnum::checkBlankRule($value['blank_rule'])) {
            return false;
        }
        return true;

    }

    //检验定义问卷参数中 题型3（单项填空）的语义正确性
    private static function checkIdentifyType3($value)
    {
        return true;
    }

    //检验定义问卷参数中 题型4（矩阵单选）的语义正确性
    private static function checkIdentifyType4($value)
    {
        if ($value['option_num'] != count($value['option'])) {
            return false;
        }
        if ($value['title_num'] != count($value['title_list'])) {
            return false;
        }
        return true;
    }
    //检验定义问卷参数中 题型7（矩阵填空）的语义正确性 
 private static function checkIdentifyType7($value)
    {
        if ($value['option_num'] != count($value['option'])) {
            return false;
        }
        // if ($value['title_num'] != count($value['title_list'])) {
        //     return false;
        // }
        return true;
    }
    //检验定义问卷参数中 题型5（打分单选）的语义正确性
    private static function checkIdentifyType5($value)
    {
        if ($value['option_num'] != count($value['option'])) {
            return false;
        }
        if ($value['option_num'] != count($value['score'])) {
            return false;
        }
        //不允许分值小于0
        foreach ($value['score'] as $v) {
            if ($v < 0) {
                return false;
            }
        }
        return true;
    }

    //检验定义问卷参数中 题型6（跳题单选）的语义正确性
    private static function checkIdentifyType6($value,$key,$formatCount)
    {
        if ($value['option_num'] != count($value['option'])) {
            return false;
        }
        if ($value['option_num'] != count($value['jump'])) {
            return false;
        }
        if(!$value['necessary']){
            echo '跳题单选必须是必答题';
            return false;
        }

        //不允许所选的跳转题号小于等于自身，且不能大于最大题号
        foreach ($value['jump'] as $v) {
            if($v === null) continue;
            if ($v <=$key ||($v>$formatCount-1)) {
                return false;
            }
        }
        return true;
    }


    /*
     * 填写问卷参数验证
     * 1.验证外层参数正确性：
     *      判断id和type是否与模板上一致
     * 2.验证验证答题数据完整性
            1.用户填写的答案中，int ，int_list， string_list这些都要在合理范围内（不同题型中的option_num,title_num,max_choice,min_choice）
            2.文本列表题中填空的数据要求
     * */
    public static function checkDoneQuestionnaireParam($param)
    {
        if(!checkValueType($param,'array')){
            // echo 0;

            return false;
        }
        //验证外层参数数据类型
        if (!self::checkDoneOutsideParam($param)) {
            // echo "外层\n";
            return false;
        }
        /*验证外层参数的语义完整性：
            验证qid是否存在*/
        
        $formatModel = QModel::get($param['qid']);
        
        if (!$formatModel) {
            echo "qid错误\n";
            return false;
        }

        //验证答题数据完整性
        // if (!self::checkDoneDataParam($param['data'], $formatModel)) {
        //     echo "内层参数错误\n";
        //     return false;
        // }
        return true;
    }

    //验证外层参数数据类型
    private static function checkDoneOutsideParam($param)
    {
        $correctData = QEnum::getDoneQuestionnaireParamRule();
        //检查参数是否缺漏
        foreach ($correctData as $key => $value) {
            if (!array_key_exists($key, $param)) {
                echo $key . "参数缺漏\n";
                return false;
            }
        }
        //检查有没有多余项
        // if (count($correctData) != count($param)) {
        //     echo "有多余参数\n";
        //     return false;
        // }

        //检查参数项是否符合类型
        // foreach ($param as $key => $value) {
        //     if (!checkValueType($value, $correctData[$key])) {
        //         echo $key . "数据类型错误\n";
        
        //         return false;
        //     }
        // }
        return true;
    }

    //验证答题数据完整性
    private static function checkDoneDataParam($data, $formatModel)
    {
        $correctData = QEnum::getDoneQuestionnaireDataRule();

        $id_list=[];//用于判断必做题是否都做了
        $jumpStart=count($data);//默认不跳题
        $jumpEnd=count($data);//默认不跳题
        $preIndex=-1;//保证顺序

        $formatModel['format'] = json_decode($formatModel['format'],true);
        // var_dump($formatModel['format']);
        //检查每一题
        foreach ($data as  $value) {
            // var_dump('foreach',$value);
            //保证id的存在性
            if (!array_key_exists('id', $value) || !array_key_exists($value['id'], $formatModel['format'])) {
                echo 'id错误';
                return false;
            }
            if($value['id']<=$preIndex){
                echo "题目顺序不对";
                return false;
            }
            $preIndex=$value['id'];
            //判断是否有需要跳题的题目出现
            // if($value['id']>$jumpStart && $value['id']<$jumpEnd){
            //     echo '出现了需要跳题的题目,id为'.$value['id'];
            //     return false;
            // }

            //保证type的存在性
            if (!array_key_exists('type', $value) || !array_key_exists($value['type'], $correctData)) {
                echo 'type错误1';
                return false;
            }
            array_push($id_list,$value['id']);
            //判断type真实性
            if ($formatModel['format'][$value['id']]['type'] != $value['type']) {
                echo 'type错误2';
                return false;
            }
            $correct = $correctData[$value['type']];

            //检查项数
            if (count($correct) != count($value)) {
                echo $value['id'].'题目答案项数不对';
                return false;
            }

            //
            //检查参数是否符合语义(对不同的题型有不同处理)
            switch ($value['type']) {
                case 0:
                    if (!self::checkDoneType0($value, $formatModel['format'][$value['id']])) {
                        echo "id:".$value['id']."题型0错误\n";
                        return false;
                    }
                    break;
                case 1:
                    if (!self::checkDoneType1($value, $formatModel['format'][$value['id']])) {
                        echo "id:".$value['id']."题型1错误\n";
                        return false;
                    }
                    break;
                case 2:
                    if (!self::checkDoneType2($value, $formatModel['format'][$value['id']])) {
                        echo "id:".$value['id']."题型2错误\n";
                        return false;
                    }
                    break;
                case 3:
                    if (!self::checkDoneType3($value, $formatModel['format'][$value['id']])) {
                        echo "id:".$value['id']."题型3错误\n";
                        return false;
                    }
                    break;
                case 4:
                    if (!self::checkDoneType4($value, $formatModel['format'][$value['id']])) {
                        echo "id:".$value['id']."题型4错误\n";
                        return false;
                    }
                    break;
                case 5:
                    if (!self::checkDoneType5($value, $formatModel['format'][$value['id']])) {
                        echo "id:".$value['id']."题型5错误\n";
                        return false;
                    }
                    break;
                case 6:
                    if (!self::checkDoneType6($value, $formatModel['format'][$value['id']])) {
                        echo "id:".$value['id']."题型6错误\n";
                        return false;
                    }
                    //如果跳题，要把中间的题目都加到$id_list，并更新$jumpStart和$jumpEnd
                    $jumpStart=$value['id'];
                    $jumpEnd=$formatModel['format'][$value['id']]['jump'][$value['choice']];
                    for($i=$jumpStart+1;$i<$jumpEnd;$i++){
                        array_push($id_list,$i);
                    }
                    break;
                default:
                    return false;
            }
            //echo $value['id']."ok\n";
        }
        //检测必做题有没有缺失
        foreach ($formatModel['format'] as $key=>$value){
            if($value['type']==5||$value['necessary']){
                if(!in_array($key,$id_list)){
                    return false;
                }
            }
        }
        return true;
    }


    //检验定义问卷参数中 题型0（单选）的语义正确性
    private static function checkDoneType0($value, $topic)
    {
        if (!array_key_exists('choice', $value)) {
            return false;
        }
        //检查数据类型
        if (!checkValueType($value['choice'], 'int')) {
            return false;
        }
        //选项在给定的范围之内
        if (!array_key_exists($value['choice'], $topic['option'])) {
            return false;
        }
        //如果有其他选项,且选择了其他选项，必须要填入"other_str",否则填空字符串
        if($topic['other_option']!=-1 && $value['choice']==$topic['other_option']){
            if(!$value['other_str']){
                return false;
            }
        }
        return true;
    }

    //检验定义问卷参数中 题型1（多选）的语义正确性
    private static function checkDoneType1($value, $topic)
    {
        if (!array_key_exists('choice_list', $value)) {
            echo '无choice_list';
            return false;
        }
        //检查数据类型
        if (!checkValueType($value['choice_list'], 'int_list')) {
            echo 'choice_list类型不正确';
            return false;
        }
        //选项在给定的范围之内
        foreach ($value['choice_list'] as $k => $v) {
            if (!array_key_exists($v, $topic['option'])) {
                echo $v.'选项超出范围';
                return false;
            }
        }
        //不能有重复选择
        if(checkHasSameValueInList($value['choice_list'])){
            echo "多選題答案中有相同选项\n";
            return false;
        }
        //选择的数量正确
        if ($topic['min_choice'] > count($value['choice_list']) || count($value['choice_list']) > $topic['max_choice']) {
            echo '选项数量不正确';
            return false;
        }
        //如果有其他选项,且有选择了其他选项，必须要填入"other_str",否则填空字符串
        if($topic['other_option']!=-1 && in_array($topic['other_option'],$value['choice_list'])){
            if(!(bool)$value['other_str']){
                echo '缺少other_option';
                return false;
            }
        }
        // else{
        //     if((bool)$value['other_str']){
        //         echo '不能有other_option';
        //         return false;
        //     }
        // }
        return true;
    }

    //检验定义问卷参数中 题型2（填空列表）的语义正确性
    private static function checkDoneType2($value, $topic)
    {
        if (!array_key_exists('answer_list', $value)) {
            echo 0;
            return false;
        }
        //填空数要正确
        if (count($value['answer_list']) != $topic['blank_num']) {
            echo 1;
            return false;
        }
        //检查数据类型
        if (!checkValueType($value['answer_list'], 'array')) {
            echo 2;
            return false;
        }
        //判断每一个空的属性和值是否符合规定
        foreach ($value['answer_list'] as $k => $v) {
            $type = $topic['blank_rule'][$k]['type'];
            switch ($type) {
                case 0://数字
                    if (!checkValueType($v, 'int') || $topic['blank_rule'][$k]['min'] > $v || $v > $topic['blank_rule'][$k]['max']) {
                        echo "数字属性出错";
                        return false;
                    }
                    break;
                case 1://文本
                    if (!checkValueType($v, 'string')) {
                        return false;
                    }
                    $len = getWordNum($v);
                    if (($topic['blank_rule'][$k]['min'] > $len) ||  ($len > $topic['blank_rule'][$k]['max'])) {
                        echo "文本属性出错";
                        return false;
                    }
                    break;
                case 2://电话
                    if (!checkValueType($v, 'phone_number')) {
                        echo "电话属性出错";
                        return false;
                    }
                    break;
            }

        }
        return true;

    }

    //检验定义问卷参数中 题型3（单项填空）的语义正确性
    private static function checkDoneType3($value, $topic)
    {
        if (!array_key_exists('answer', $value)) {
            return false;
        }
        return true;
    }

    //检验定义问卷参数中 题型4（矩阵单选）的语义正确性
    private static function checkDoneType4($value, $topic)
    {

        if (!array_key_exists('answer_list', $value)) {
            return false;
        }
        //每个选项都在范围内
        foreach ($value['answer_list'] as $v){
            if (!array_key_exists($v, $topic['option'])) {
                return false;
            }
        }
        if ($topic['title_num'] != count($value['answer_list'])) {
            return false;
        }
        return true;
    }

    //检验定义问卷参数中 题型5（打分单选）的语义正确性
    private static function checkDoneType5($value, $topic)
    {
        if (!array_key_exists('choice', $value)) {
            return false;
        }
        //检查数据类型
        if (!checkValueType($value['choice'], 'int')) {
            return false;
        }
        //选项在给定的范围之内
        if (!array_key_exists($value['choice'], $topic['option'])) {
            return false;
        }
        return true;
    }
    //检验定义问卷参数中 题型6（跳题单选）的语义正确性
    private static function checkDoneType6($value, $topic)
    {
        if (!array_key_exists('choice', $value)) {
            return false;
        }
        //检查数据类型
        if (!checkValueType($value['choice'], 'int')) {
            return false;
        }
        //选项在给定的范围之内
        if (!array_key_exists($value['choice'], $topic['option'])) {
            return false;
        }
        return true;
    }
}